package com.stars.module.grant.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.stars.base.constants.SeparatorConstants;
import com.stars.base.entity.CommonDTO;
import com.stars.module.grant.entity.GrantEnum;
import com.stars.module.grant.entity.GrantTargetEnum;
import com.stars.module.grant.entity.StarGrant;
import com.stars.module.grant.mapper.StarGrantMapper;
import com.stars.module.grant.service.StarGrantService;
import com.stars.module.privilege.mapper.StarPrivilegeMapper;
import com.stars.module.role.mapper.StarRoleMapper;
import com.stars.util.common.DevelopKit;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author : moon
 * @version : 1.0
 * @date : 2023/03/22
 * @description : 权限相关服务实现类
 */
@Service
public class StarGrantServiceImpl extends ServiceImpl<StarGrantMapper, StarGrant> implements StarGrantService {

    private final StarGrantMapper mapper;
    private final StarPrivilegeMapper privilegeMapper;
    private final StarRoleMapper roleMapper;

    private final SqlSessionFactory sqlSessionFactory;

    public StarGrantServiceImpl(StarGrantMapper mapper, StarPrivilegeMapper privilegeMapper, StarRoleMapper roleMapper, SqlSessionFactory sqlSessionFactory) {
        this.mapper = mapper;
        this.privilegeMapper = privilegeMapper;
        this.roleMapper = roleMapper;
        this.sqlSessionFactory = sqlSessionFactory;
    }

    /**
     * 查询权限角色关联数据
     * @author : moon
     * @date :  2023/3/29 11:19
     * @param: dto 查询条件
     * @param: targetType 权限绑定类型
     * @return: com.alibaba.fastjson2.JSONObject
     */
    @Override
    public JSONObject loadGrantTargetList(CommonDTO dto, String targetType) {

        Page<StarGrant> page = Page.of(dto.getCurrent(), dto.getPageSize());

        LambdaQueryWrapper<StarGrant> query = new LambdaQueryWrapper<>();

        query.eq(StarGrant::getSourceId, dto.getFid())
                .eq(StarGrant::getTargetType, targetType)
                .like(StarGrant::getTargetName, dto.getSearch());

        query.orderByAsc(StarGrant::getShowOrder);

        Page<StarGrant> grantPage = mapper.selectPage(page, query);

        JSONObject result = new JSONObject();

        result.put("list", grantPage.getRecords());
        result.put("total", grantPage.getTotal());

        return result;
    }

    @Override
    public List<StarGrant> getGrantData(String fid, Integer type) {

        LambdaQueryWrapper<StarGrant> query = new LambdaQueryWrapper<>();

        query.eq(StarGrant::getSourceId, fid);
        query.eq(StarGrant::getSourceType,type);

        return this.list(query);
    }

    @Override
    public boolean saveGrant(String sourceId, String targetType, List<StarGrant> list) {

        String sourceName = "";

        if(list != null && list.size()>0){
            Integer grantType = list.get(0).getSourceType();
            //权限授权角色
            if(GrantEnum.PRIVILEGE.getIntValue() == grantType){
                sourceName = privilegeMapper.selectById(sourceId).getPrivilegeName();
            }
            //角色授权用户
            else if(GrantEnum.ROLE.getIntValue() == grantType){
                sourceName = roleMapper.selectById(sourceId).getRoleName();
            }
        }

        return handleGrant(sourceId, targetType, sourceName, list);
    }


    /**
     * 角色/用户/权限授权保存，批量先修改后保存
     * @param privilegeId 权限ID
     * @param targetType 权限绑定类型
     * @param list 授权信息
     */
    private boolean handleGrant(String privilegeId, String targetType, String sourceName, List<StarGrant> list){

        boolean result = true;
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        StarGrantMapper starGrantMapper = sqlSession.getMapper(StarGrantMapper.class);
        try {
            // 清空数据重新插入
            starGrantMapper.deleteGrantByType(privilegeId, Integer.parseInt(targetType));

            for(StarGrant starGrant: list){
                starGrant.setId(DevelopKit.generateUUID());
                starGrant.setSourceName(sourceName);
                DevelopKit.setBaseInfo(starGrant);

                starGrantMapper.insert(starGrant);
            }
            sqlSession.commit();

        }catch (Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            result = false;
        }finally {
            try {
                sqlSession.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return result;
    }

    @Override
    public boolean deleteGrantDataById(String id) {

        return mapper.deleteGrantDataById(id);
    }

    @Override
    public boolean checkRoleGrant(String roleId) {

        LambdaQueryWrapper<StarGrant> query = new LambdaQueryWrapper<>();

        query.eq(StarGrant::getSourceId,roleId);

        return mapper.exists(query);
    }

    @Override
    public String loadUserRoles(String userId) {

        List<StarGrant> starGrants = this.getGrantByTarget(userId, GrantEnum.ROLE.getValue());

        return starGrants.stream().map(StarGrant::getSourceId).distinct().collect(Collectors.joining(SeparatorConstants.COMMA_SEPARATOR));
    }

    @Override
    public String loadUserPrivileges(String userId) {

        // 先查询直接授权权限的信息
        List<StarGrant> starGrants = this.getGrantByTarget(userId, GrantEnum.PRIVILEGE.getValue());

        // 然后查询权限授权给角色，然后角色授权给当前用户的
        starGrants.addAll(mapper.queryPrivilegeByRole(userId));

        return starGrants.stream().map(StarGrant::getSourceId).distinct().collect(Collectors.joining(SeparatorConstants.COMMA_SEPARATOR));
    }

    /**
     * 根据授权目标，获取该目标指定类型源
     * @author : Rocks
     * @date :  2023/7/16 15:20
     * @param targetId 授权目标ID
     * @param sourceType 授权类型 1角色，2权限
     * @return List<StarGrant>
     */
    private List<StarGrant> getGrantByTarget (String targetId, String sourceType) {

        LambdaQueryWrapper<StarGrant> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(StarGrant::getTargetId,targetId)
                .eq(StarGrant::getSourceType, sourceType);

        return mapper.selectList(wrapper);
    }

}
